package com.fanqj.resilience4j.controller;

import com.fanqj.resilience4j.service.ITestService;
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
import io.vavr.CheckedRunnable;
import io.vavr.control.Try;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.function.Supplier;

/**
 * 限流器
 * @author <a href="mailto:fanqijin@wxchina.com">fanqj</a>
 * @Date 2021年01月27日 10:06
 * @Version 6.4.1
 */
@RestController
@RequestMapping("/rateLimiter")
public class RateLimiterController {

    public static final Logger logger = LoggerFactory.getLogger(RateLimiterController.class);

    @Autowired
    private ITestService iTestService;

    private RateLimiter rateLimiter;

    @PostConstruct
    private void init() {
        // 创建限流器的自定义配置
        RateLimiterConfig config = RateLimiterConfig.custom()
                //线程等待权限的默认等待时间,默认5秒
                .timeoutDuration(Duration.ofSeconds(1L))
                //限流器刷新一次间隔，刷新后将允许处理的最大请求数量重置为limitForPeriod，默认500μs
                .limitRefreshPeriod(Duration.ofSeconds(10))
                //在一次刷新周期内，允许执行的最大请求数 默认50
                .limitForPeriod(2)
                .build();
        RateLimiterRegistry registry = RateLimiterRegistry.of(config);
        rateLimiter = registry.rateLimiter("RateLimit-A");
        rateLimiter.getEventPublisher()
                .onSuccess(event -> logger.info("success"))
                .onFailure(event -> logger.warn("fail"));
    }

    @GetMapping("/test")
    public String testRateLimiter() {
        Supplier<String> decorateSupplier = RateLimiter
                .decorateSupplier(rateLimiter, () -> iTestService.testRateLimit("RateLimit"));
        String result = Try.ofSupplier(decorateSupplier)
                .recover(throwable -> "Don`t have permitted!")
                .get();
        return result;
    }

    @GetMapping("/refresh")
    public void refreshRateLimiter(@RequestParam(value = "limit") int limit, @RequestParam(value = "timeout") long timeout) {
        rateLimiter.changeLimitForPeriod(limit);
        rateLimiter.changeTimeoutDuration(Duration.ofSeconds(timeout));
    }
}
